﻿using GriffinPowerMate;
using lightwaverf;
using LightwaveRF;
using System;
using System.Drawing;
using System.Windows.Forms;

namespace PowermateLights
{
    /// <summary>
    /// Main class controls the lights in response to PowerMate events
    /// Thanks to Thomas H@mmer http://thammer.net/?p=374 for guide and lib on connecting to power mate
    /// </summary>
    public partial class PowermateLightTray: IDisposable
    {
        /// <summary>
        /// Timer for checking connection state change.
        /// </summary>
        Timer connectionTimer = new Timer();
        /// <summary>
        /// Create a new instance of the assembly that handles the HID connection.
        /// </summary>
        private PowerMateManager powerMateManager = new PowerMateManager();

        /// <summary>
        /// Records the last known dim level of the associated lightwaverf device.
        /// </summary>
        int dimlevel = -100000;
        /// <summary>
        /// Incremented/decremented based on Powermate rotation change. Allows update in steps in
        /// order to avoid overloading the UDP interface.
        /// </summary>
        int dimAmount = 0;
        /// <summary>
        /// LightWaveRF has no state tracking so no way to know startup state
        /// </summary>
        State lightstate = State.unknown;

        /// <summary>
        /// Creates a new instance of the powermateLightTray class and initializes the variables.
        /// </summary>
        public PowermateLightTray()
        {
            //configure the timer used to detect when the powermate becomes attached
            connectionTimer.Interval = 500;
            connectionTimer.Tick += new EventHandler(connectionTimer_Tick);
            connectionTimer.Start();
        }

        /// <summary>
        /// Event called when the user chooses the Lights off icon menu item.
        /// </summary>
        /// <param name="sender">Object that sent the exit message.</param>
        /// <param name="e">Event arguments of the click event.</param>
        public void OnLightOff(object sender, EventArgs e)
        {
            //Track the dim level as being set to off
            dimlevel = 0;
            //Set the light off - LightwaveRF API call
            API.DeviceOnOff(GetLightwaveRFID(Properties.Settings.Default.RoomNum), 
                GetLightwaveRFID(Properties.Settings.Default.DeviceNum),
                State.Off);
            //Update state tracking
            lightstate = State.Off;
        }

        /// <summary>
        /// Event called when the user chooses the Lights on icon menu item.
        /// Turns the light onto the last dim level in the light switch memory.
        /// </summary>
        /// <param name="sender">Object that sent the exit message.</param>
        /// <param name="e">Event arguments of the click event.</param>
        public void OnLightOn(object sender, EventArgs e)
        {
            //Set the light on - LightwaveRF API call.
            API.DeviceOnOff(GetLightwaveRFID(Properties.Settings.Default.RoomNum), 
                GetLightwaveRFID(Properties.Settings.Default.DeviceNum),
                State.On);
            //Update state tracking
            lightstate = State.On;
        }

        /// <summary>
        /// Event called when the user chooses the Lights on icon menu item.
        /// Turns the light onto full.
        /// </summary>
        /// <param name="sender">Object that sent the exit message.</param>
        /// <param name="e">Event arguments of the click event.</param>
        public void OnLightFull(object sender, EventArgs e)
        {
            //Update the current dim level to max.
            //Only dim down will work
            dimlevel = 100;
            //Set the light dim level to max power - LightwaveRF API call.
            API.Dim(GetLightwaveRFID(Properties.Settings.Default.RoomNum),
                GetLightwaveRFID(Properties.Settings.Default.DeviceNum),
                100);
            //Update state tracking
            lightstate = State.On;
        }

        /// <summary>
        /// Handles the timer tick to attempt to connect and update the icon status.
        /// </summary>
        /// <param name="sender">Object that sent the exit message.</param>
        /// <param name="e">Event arguments of the click event.</param>
        private void connectionTimer_Tick(object sender, EventArgs e)
        {
            //Send the connect message and get the state back
            bool connected = ConnectToPowerMate();
            if (connected)
            {
                //Connected - stop the timer
                connectionTimer.Stop();
                //Update the icon with the connected icon.
                Program.trayIcon.Icon = Properties.Resources.connected;
            }
        }

        /// <summary>
        /// Calls the HID API and attempts to connect to a valid Powermate.
        /// If successful then setup the event handlers and return true.
        /// else return false.
        /// </summary>
        /// <returns>Connection successful</returns>
        private bool ConnectToPowerMate()
        {
            //Attempt connection
            if (powerMateManager.OpenDevice())
            {
                //Setup the event handlers
                powerMateManager.DeviceAttached += powerMate_DeviceAttached;
                powerMateManager.DeviceRemoved += powerMate_DeviceRemoved;
                powerMateManager.KnobDisplacement += powerMate_KnobDisplacement;
                //Return connection successful
                return true;
            }
            else
            {
                //Connection failed.
                return false;
            }
        }

        /// <summary>
        /// Event occurs when the attached powermate is no longer connected or responsive.
        /// </summary>
        /// <param name="sender">Object that sent the exit message.</param>
        /// <param name="e">Event arguments of the click event.</param>
        private void powerMate_DeviceRemoved(object sender, EventArgs e)
        {
            //Update the icon to reflect connection status
            Program.trayIcon.Icon = Properties.Resources.Disconnected;
            System.Diagnostics.Debug.WriteLine("PowerMate removed.");
        }

        /// <summary>
        /// Event occurs when the powermate device becomes connected or responsive
        /// </summary>
        /// <param name="sender">Object that sent the exit message.</param>
        /// <param name="e">Event arguments of the click event.</param>
        private void powerMate_DeviceAttached(object sender, EventArgs e)
        {
            //Update the icon to reflect connection status
            Program.trayIcon.Icon = Properties.Resources.connected;
            System.Diagnostics.Debug.WriteLine("PowerMate attached.");
        }

        /// <summary>
        /// Event handles knob displacement and the effect on the lights.
        /// Use the button state, if down then check if dim up or down.
        /// Dim lights in state.
        /// </summary>
        /// <param name="sender">Object that sent the exit message.</param>
        /// <param name="e">Event arguments of the click event.</param>
        private void powerMate_KnobDisplacement(object sender,
            PowerMateEventArgs e)
        {
            if ((Properties.Settings.Default.ButtonStateTriggerDown && e.State.ButtonState == PowerMateButtonState.Down) ||
                (!Properties.Settings.Default.ButtonStateTriggerDown && e.State.ButtonState == PowerMateButtonState.Up))
            {
                if (dimlevel < 0)
                {
                    dimlevel = 10;

                    API.Dim(GetLightwaveRFID(Properties.Settings.Default.RoomNum), 
                        GetLightwaveRFID(Properties.Settings.Default.DeviceNum), 
                        dimlevel);
                }
                else
                {
                    dimAmount += (e.State.KnobDisplacement * 2);
                    
                    if ((dimAmount < -5 || dimAmount > 5) && dimlevel <= 100)
                    {
                        if ( (dimlevel + dimAmount) <= 0)
                        {
                            dimlevel = 0;
                            API.DeviceOnOff(GetLightwaveRFID(Properties.Settings.Default.RoomNum), 
                                GetLightwaveRFID(Properties.Settings.Default.DeviceNum), 
                                State.Off);
                            lightstate = State.Off;
                        }
                        else if (lightstate != State.Off || (dimlevel + dimAmount) > 0)
                        {
                            dimlevel += (dimAmount);
                            if (dimlevel > 100) dimlevel = 100;
                            else if (dimlevel < 0) dimlevel = 0;
                            API.Dim(GetLightwaveRFID(Properties.Settings.Default.RoomNum), 
                                GetLightwaveRFID(Properties.Settings.Default.DeviceNum), 
                                dimlevel);
                            if (dimlevel > 0) lightstate = State.On;
                            else lightstate = State.Off;
                        }
                        dimAmount = 0;
                    }
                }
                //dim or increase light
                
            }
        }

        private void powerMate_ButtonUp(object sender, PowerMateEventArgs e)
        {
            UpdateGUIFromState(e.State);
        }

        private void powerMate_ButtonDown(object sender, PowerMateEventArgs e)
        {
            UpdateGUIFromState(e.State);
        }

        private void UpdateGUIFromState(PowerMateState state)
        {
            //Not in use
        }

        public void Dispose()
        {
                powerMateManager.CloseDevice();
                powerMateManager.Dispose();
            
        }

        private int GetLightwaveRFID(string id)
        {
            if (string.IsNullOrEmpty(id))
                return 0;
            int result = -1;
            if (int.TryParse(id, out result))
            {
                return result;
            }
            else return 0;
        }
    }
}
